package com.kancy.okhttp.client.support;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.Objects;

/**
 * @author kancy
 * @date 7/19/2019 09:16
 */
public class HttpClientLogInterceptor implements ClientHttpRequestInterceptor {

    private static Logger log = LoggerFactory.getLogger(HttpClientLogInterceptor.class);

    private static final String TRANCE_NAME_TRACE_ID = "X-B3-TraceId";
    private static final String TRANCE_NAME_SPAN_ID = "X-B3-SpanId";
    private static final String TRANCE_NAME_PARENT_SPAN_ID = "X-B3-ParentSpanId";

    /**
     * 本地的ip地址
     */
    private static final String LOCAL_IP = getLocalIp();

    /**
     * Intercept the given request, and return a response
     * @param request
     * @param body
     * @param execution
     * @return
     * @throws IOException
     */
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body,
                                        ClientHttpRequestExecution execution) throws IOException {
        HttpClientRequestLog httpClientRequestLog = initHttpRequestLog(request, body);
        // 设置Trace
        httpClientRequestLog.setTraceId(request.getHeaders().getFirst(TRANCE_NAME_TRACE_ID));
        httpClientRequestLog.setSpanId(request.getHeaders().getFirst(TRANCE_NAME_SPAN_ID));
        httpClientRequestLog.setParentSpanId(request.getHeaders().getFirst(TRANCE_NAME_PARENT_SPAN_ID));
        // 接口调用
        long start = System.currentTimeMillis();
        ClientHttpResponse response = execution.execute(request, body);
        long end = System.currentTimeMillis();
        // 设置耗时
        httpClientRequestLog.setConsumeTime(end - start);
        // 设置返回码
        httpClientRequestLog.setResponseCode(response.getStatusCode().value());
        // 设置返回数据
        setResponseBody(response, httpClientRequestLog);
        log.info(JSON.toJSONString(httpClientRequestLog));
        return response;
    }

    /**
     * 初始化 HttpClientRequestLog
     * @param request
     * @param body
     * @return
     */
    private HttpClientRequestLog initHttpRequestLog(HttpRequest request, byte[] body) {
        HttpClientRequestLog httpClientRequestLog = new HttpClientRequestLog();
        httpClientRequestLog.setRequestBody(new String(body, StandardCharsets.UTF_8));
        httpClientRequestLog.setRequestUrl(request.getURI().toString());
        httpClientRequestLog.setLocalAddress(LOCAL_IP);
        return httpClientRequestLog;
    }

    /**
     * 设置返回体
     * @param response
     * @param httpClientRequestLog
     * @return
     * @throws IOException
     */
    private ClientHttpResponse setResponseBody(ClientHttpResponse response, HttpClientRequestLog httpClientRequestLog) throws IOException {
        if (Objects.nonNull(response)){
            try {
                httpClientRequestLog.setResponseCode(response.getStatusCode().value());
                BufferingClientHttpResponseWrapper responseWrapper = new BufferingClientHttpResponseWrapper(response);
                httpClientRequestLog.setResponseBody(StreamUtils.copyToString(responseWrapper.getBody(), StandardCharsets.UTF_8));
                return responseWrapper;
            } catch (IOException io) {
                return response;
            }
        }
        return response;
    }

    private static String getLocalIp() {
        InetAddress inetAddress = null;
        try {
            Enumeration netInterfaces = NetworkInterface.getNetworkInterfaces();
            while(netInterfaces.hasMoreElements()) {
                NetworkInterface ni = (NetworkInterface)netInterfaces.nextElement();
                Enumeration ips = ni.getInetAddresses();
                while(ips.hasMoreElements()) {
                    inetAddress = (InetAddress) ips.nextElement();
                    if (Objects.nonNull(inetAddress)) {
                        String ip = inetAddress.getHostAddress();
                        if (!StringUtils.isEmpty(ip) && !ip.contains(":") && !Objects.equals("127.0.0.1", ip)) {
                            String displayName = ni.getDisplayName();
                            if (displayName!=null && displayName.contains("Virtual")){
                                continue;
                            }
                            if (ip.endsWith(".1")){
                                continue;
                            }
                            return ip;
                        }
                    }
                }
            }
            inetAddress = InetAddress.getLocalHost();
        } catch (Exception e) {
            log.warn("获取本地Ip地址失败：{}", e.getMessage());
        }
        return inetAddress.getHostAddress();
    }
}
